package com.btsi.contract;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.v3.client.Client;
import org.fisco.bcos.sdk.v3.codec.datatypes.Address;
import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes;
import org.fisco.bcos.sdk.v3.codec.datatypes.Event;
import org.fisco.bcos.sdk.v3.codec.datatypes.Function;
import org.fisco.bcos.sdk.v3.codec.datatypes.Type;
import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple3;
import org.fisco.bcos.sdk.v3.contract.Contract;
import org.fisco.bcos.sdk.v3.crypto.CryptoSuite;
import org.fisco.bcos.sdk.v3.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.v3.model.CryptoType;
import org.fisco.bcos.sdk.v3.model.TransactionReceipt;
import org.fisco.bcos.sdk.v3.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException;

@SuppressWarnings("unchecked")
public class ProxyAdmin extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b50600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350610890806100616000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b3660046105f2565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d161023c565b005b3480156100df57600080fd5b506100d16100ee366004610616565b6102b9565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f366004610665565b610343565b34801561013057600080fd5b506100d161013f366004610616565b6103d4565b34801561015057600080fd5b506100d161015f3660046105f2565b61042c565b34801561017057600080fd5b506100a061017f3660046105f2565b610516565b60007f5c60da1b04210c25e1974b6edfcf5bb7c7365b6a88c42319fcbd024464075cc281806001600160a01b0385166101c3635c60da1b60e01b610551565b6040516101d0919061076b565b600060405180830381855afa9150503d806000811461020b576040519150601f19603f3d011682016040523d82523d6000602084013e610210565b606091505b50915091508161021f57600080fd5b808060200190518101906102339190610787565b95945050505050565b6000546001600160a01b0316331461026f5760405162461bcd60e51b8152600401610266906107a4565b60405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031633146102e35760405162461bcd60e51b8152600401610266906107a4565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561032757600080fd5b505af115801561033b573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461036d5760405162461bcd60e51b8152600401610266906107a4565b60405163278f794360e11b81526001600160a01b03841690634f1ef28690349061039d90869086906004016107d9565b6000604051808303818588803b1580156103b657600080fd5b505af11580156103ca573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146103fe5760405162461bcd60e51b8152600401610266906107a4565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161030d565b6000546001600160a01b031633146104565760405162461bcd60e51b8152600401610266906107a4565b6001600160a01b0381166104bb5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610266565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60007ff851a44064d54ebc488774050c771bacc14f01dd7456abacb48978dba9cd92a481806001600160a01b0385166101c36303e1469160e61b5b6040805160048082528183019092526060916000919060208201818036833701905050905060005b60048110156105d3578381600481106105945761059461081b565b1a60f81b8282815181106105aa576105aa61081b565b60200101906001600160f81b031916908160001a905350806105cb81610831565b915050610579565b5092915050565b6001600160a01b03811681146105ef57600080fd5b50565b60006020828403121561060457600080fd5b813561060f816105da565b9392505050565b6000806040838503121561062957600080fd5b8235610634816105da565b91506020830135610644816105da565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561067a57600080fd5b8335610685816105da565b92506020840135610695816105da565b9150604084013567ffffffffffffffff808211156106b257600080fd5b818601915086601f8301126106c657600080fd5b8135818111156106d8576106d861064f565b604051601f8201601f19908116603f011681019083821181831017156107005761070061064f565b8160405282815289602084870101111561071957600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60005b8381101561075657818101518382015260200161073e565b83811115610765576000848401525b50505050565b6000825161077d81846020870161073b565b9190910192915050565b60006020828403121561079957600080fd5b815161060f816105da565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60018060a01b0383168152604060208201526000825180604084015261080681606085016020870161073b565b601f01601f1916919091016060019392505050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561085357634e487b7160e01b600052601160045260246000fd5b506001019056fea2646970667358221220f476616c8655ddb86a4e0eb97815db07902ffd52bfb5216954f55b76f9b126b764736f6c634300080b0033"};

    public static final String BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b50600080546001600160a01b031916339081178255604051909182917f5c7c30d4a0f08950cb23be4132957b357fa5dfdb0fcf218f81b86a1c036e47d0908290a350610895806100616000396000f3fe60806040526004361061007b5760003560e01c8063d366253d1161004e578063d366253d14610118578063d42d0f4f14610138578063d86e29e214610158578063db1fc60c1461016d57600080fd5b806316cad12a146100805780635089e2c8146100a25780635defeee3146100d85780636c57245d146100f8575b600080fd5b34801561008c57600080fd5b506100a061009b3660046105f7565b610180565b005b3480156100ae57600080fd5b506000546001600160a01b03165b6040516001600160a01b03909116815260200160405180910390f35b3480156100e457600080fd5b506100bc6100f33660046105f7565b610275565b34801561010457600080fd5b506100bc6101133660046105f7565b61032d565b34801561012457600080fd5b506100a061013336600461061b565b61036b565b34801561014457600080fd5b506100a061015336600461061b565b6103f6565b34801561016457600080fd5b506100a061044f565b6100a061017b36600461066a565b6104c4565b6000546001600160a01b031633146101b457604051636381e58960e11b81526004016101ab90610740565b60405180910390fd5b6001600160a01b03811661021a57604051636381e58960e11b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016101ab565b600080546040516001600160a01b03808516939216917f5c7c30d4a0f08950cb23be4132957b357fa5dfdb0fcf218f81b86a1c036e47d091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60007fd5696bb175b326f8ce5dbe1ba5f41da312aed21a7f90cc42d40b8a20f2004c7181806001600160a01b0385166102b463d5696bb160e01b610556565b6040516102c191906107a5565b600060405180830381855afa9150503d80600081146102fc576040519150601f19603f3d011682016040523d82523d6000602084013e610301565b606091505b50915091508161031057600080fd5b8080602001905181019061032491906107c1565b95945050505050565b60007ff15228001de5006b7e364229f9fb3c2f54a1e8f2aa8887d686ce09f2f04fc23181806001600160a01b0385166102b4621e2a4560eb1b610556565b6000546001600160a01b0316331461039657604051636381e58960e11b81526004016101ab90610740565b604051633a2a322560e21b81526001600160a01b03828116600483015283169063e8a8c894906024015b600060405180830381600087803b1580156103da57600080fd5b505af11580156103ee573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0316331461042157604051636381e58960e11b81526004016101ab90610740565b60405163333b0add60e11b81526001600160a01b03828116600483015283169063667615ba906024016103c0565b6000546001600160a01b0316331461047a57604051636381e58960e11b81526004016101ab90610740565b600080546040516001600160a01b03909116907f5c7c30d4a0f08950cb23be4132957b357fa5dfdb0fcf218f81b86a1c036e47d0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031633146104ef57604051636381e58960e11b81526004016101ab90610740565b60405163207fa8b960e01b81526001600160a01b0384169063207fa8b990349061051f90869086906004016107de565b6000604051808303818588803b15801561053857600080fd5b505af115801561054c573d6000803e3d6000fd5b5050505050505050565b6040805160048082528183019092526060916000919060208201818036833701905050905060005b60048110156105d85783816004811061059957610599610820565b1a60f81b8282815181106105af576105af610820565b60200101906001600160f81b031916908160001a905350806105d081610836565b91505061057e565b5092915050565b6001600160a01b03811681146105f457600080fd5b50565b60006020828403121561060957600080fd5b8135610614816105df565b9392505050565b6000806040838503121561062e57600080fd5b8235610639816105df565b91506020830135610649816105df565b809150509250929050565b63b95aa35560e01b600052604160045260246000fd5b60008060006060848603121561067f57600080fd5b833561068a816105df565b9250602084013561069a816105df565b9150604084013567ffffffffffffffff808211156106b757600080fd5b818601915086601f8301126106cb57600080fd5b8135818111156106dd576106dd610654565b604051601f8201601f19908116603f0116810190838211818310171561070557610705610654565b8160405282815289602084870101111561071e57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60005b83811015610790578181015183820152602001610778565b8381111561079f576000848401525b50505050565b600082516107b7818460208701610775565b9190910192915050565b6000602082840312156107d357600080fd5b8151610614816105df565b60018060a01b0383168152604060208201526000825180604084015261080b816060850160208701610775565b601f01601f1916919091016060019392505050565b63b95aa35560e01b600052603260045260246000fd5b60006000198214156108585763b95aa35560e01b600052601160045260246000fd5b506001019056fea26469706673582212208150299ee9d681a151e754e5c2cb5d848c173386a74593edd16e82b8222bcb0e64736f6c634300080b0033"};

    public static final String SM_BINARY = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeProxyAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.v3.utils.StringUtils.joinAll("", ABI_ARRAY);

    public static final String FUNC_CHANGEPROXYADMIN = "changeProxyAdmin";

    public static final String FUNC_GETPROXYADMIN = "getProxyAdmin";

    public static final String FUNC_GETPROXYIMPLEMENTATION = "getProxyImplementation";

    public static final String FUNC_OWNER = "owner";

    public static final String FUNC_RENOUNCEOWNERSHIP = "renounceOwnership";

    public static final String FUNC_TRANSFEROWNERSHIP = "transferOwnership";

    public static final String FUNC_UPGRADE = "upgrade";

    public static final String FUNC_UPGRADEANDCALL = "upgradeAndCall";

    public static final Event OWNERSHIPTRANSFERRED_EVENT = new Event("OwnershipTransferred",
            Arrays.<TypeReference<?>>asList(new TypeReference<Address>(true) {}, new TypeReference<Address>(true) {}));
    ;

    protected ProxyAdmin(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public static String getABI() {
        return ABI;
    }

    public List<OwnershipTransferredEventResponse> getOwnershipTransferredEvents(
            TransactionReceipt transactionReceipt) {
        List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(OWNERSHIPTRANSFERRED_EVENT, transactionReceipt);
        ArrayList<OwnershipTransferredEventResponse> responses = new ArrayList<OwnershipTransferredEventResponse>(valueList.size());
        for (Contract.EventValuesWithLog eventValues : valueList) {
            OwnershipTransferredEventResponse typedResponse = new OwnershipTransferredEventResponse();
            typedResponse.log = eventValues.getLog();
            typedResponse.previousOwner = (String) eventValues.getIndexedValues().get(0).getValue();
            typedResponse.newOwner = (String) eventValues.getIndexedValues().get(1).getValue();
            responses.add(typedResponse);
        }
        return responses;
    }

    public TransactionReceipt changeProxyAdmin(String proxy, String newAdmin) {
        final Function function = new Function(
                FUNC_CHANGEPROXYADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String changeProxyAdmin(String proxy, String newAdmin, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_CHANGEPROXYADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForChangeProxyAdmin(String proxy, String newAdmin) {
        final Function function = new Function(
                FUNC_CHANGEPROXYADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newAdmin)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple2<String, String> getChangeProxyAdminInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_CHANGEPROXYADMIN,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, String>(

                (String) results.get(0).getValue(),
                (String) results.get(1).getValue()
                );
    }

    public String getProxyAdmin(String proxy) throws ContractException {
        final Function function = new Function(FUNC_GETPROXYADMIN,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        return executeCallWithSingleValueReturn(function, String.class);
    }

    public String getProxyImplementation(String proxy) throws ContractException {
        final Function function = new Function(FUNC_GETPROXYIMPLEMENTATION,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        return executeCallWithSingleValueReturn(function, String.class);
    }

    public String owner() throws ContractException {
        final Function function = new Function(FUNC_OWNER,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        return executeCallWithSingleValueReturn(function, String.class);
    }

    public TransactionReceipt renounceOwnership() {
        final Function function = new Function(
                FUNC_RENOUNCEOWNERSHIP,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String renounceOwnership(TransactionCallback callback) {
        final Function function = new Function(
                FUNC_RENOUNCEOWNERSHIP,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForRenounceOwnership() {
        final Function function = new Function(
                FUNC_RENOUNCEOWNERSHIP,
                Arrays.<Type>asList(),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public TransactionReceipt transferOwnership(String newOwner) {
        final Function function = new Function(
                FUNC_TRANSFEROWNERSHIP,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newOwner)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String transferOwnership(String newOwner, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_TRANSFEROWNERSHIP,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newOwner)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForTransferOwnership(String newOwner) {
        final Function function = new Function(
                FUNC_TRANSFEROWNERSHIP,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(newOwner)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple1<String> getTransferOwnershipInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_TRANSFEROWNERSHIP,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple1<String>(

                (String) results.get(0).getValue()
                );
    }

    public TransactionReceipt upgrade(String proxy, String implementation) {
        final Function function = new Function(
                FUNC_UPGRADE,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String upgrade(String proxy, String implementation, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_UPGRADE,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForUpgrade(String proxy, String implementation) {
        final Function function = new Function(
                FUNC_UPGRADE,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple2<String, String> getUpgradeInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_UPGRADE,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Address>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, String>(

                (String) results.get(0).getValue(),
                (String) results.get(1).getValue()
                );
    }

    public TransactionReceipt upgradeAndCall(String proxy, String implementation, byte[] data) {
        final Function function = new Function(
                FUNC_UPGRADEANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return executeTransaction(function);
    }

    public String upgradeAndCall(String proxy, String implementation, byte[] data,
            TransactionCallback callback) {
        final Function function = new Function(
                FUNC_UPGRADEANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForUpgradeAndCall(String proxy, String implementation,
            byte[] data) {
        final Function function = new Function(
                FUNC_UPGRADEANDCALL,
                Arrays.<Type>asList(new org.fisco.bcos.sdk.v3.codec.datatypes.Address(proxy),
                new org.fisco.bcos.sdk.v3.codec.datatypes.Address(implementation),
                new org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes(data)),
                Collections.<TypeReference<?>>emptyList(), 0);
        return createSignedTransaction(function);
    }

    public Tuple3<String, String, byte[]> getUpgradeAndCallInput(
            TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_UPGRADEANDCALL,
                Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Address>() {}, new TypeReference<DynamicBytes>() {}));
        List<Type> results = this.functionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple3<String, String, byte[]>(

                (String) results.get(0).getValue(),
                (String) results.get(1).getValue(),
                (byte[]) results.get(2).getValue()
                );
    }

    public static ProxyAdmin load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new ProxyAdmin(contractAddress, client, credential);
    }

    public static ProxyAdmin deploy(Client client, CryptoKeyPair credential) throws
            ContractException {
        return deploy(ProxyAdmin.class, client, credential, getBinary(client.getCryptoSuite()), getABI(), null, null);
    }

    public static class OwnershipTransferredEventResponse {
        public TransactionReceipt.Logs log;

        public String previousOwner;

        public String newOwner;
    }
}
